#include "ToolBox/vectorf.h"
#include <stdio.h>

/***********************************************************************/
/*                      Constructeurs                                  */
/***********************************************************************/

Vectorf::Vectorf()
{
    dimension=3;
    coordinates=new float[dimension];
    coordinates[0]=0;coordinates[1]=0;coordinates[2]=0;
}

Vectorf::Vectorf(float aX)
{
    dimension=1;
    coordinates= new float[dimension];
    coordinates[0]=aX;
}

Vectorf::Vectorf(float aX, float aY)
{
    dimension=2;
    coordinates= new float[dimension];
    coordinates[0]=aX;coordinates[1]=aY;
}

Vectorf::Vectorf(float aX, float aY, float aZ)
{
    dimension=3;
    coordinates= new float[dimension];
    coordinates[0]=aX;coordinates[1]=aY;coordinates[2]=aZ;
}

Vectorf::Vectorf(float aX, float aY, float aZ, float aW)
{
    dimension=4;
    coordinates= new float[dimension];
    coordinates[0]=aX;coordinates[1]=aY;coordinates[2]=aZ;coordinates[3]=aW;
}

Vectorf::Vectorf(float * aCoordinates, short aDimension) : dimension(aDimension)
{
	InitArray(aCoordinates);
}

Vectorf::Vectorf(const Vectorf & vec) : dimension(vec.dimension)
{
    InitArray(vec.coordinates);
}

void Vectorf::InitArray(float * aCoordinates)
{
	coordinates = new float[dimension];
	for(int i=0 ; i<dimension ; i++)
	{
            coordinates[i]=aCoordinates[i];
	}
}

/***********************************************************************/
/*                      Surcharge d'opérateur                          */
/***********************************************************************/

Vectorf & Vectorf::operator+=(const Vectorf & v)
{
    if(dimension==v.dimension)
    {
        for(int i=0;i<dimension;i++)
        {
            coordinates[i]=coordinates[i]+v.coordinates[i];
        }
    }
    return *this;
}

/***********************************************************************/
/*                      Méthodes			                           */
/***********************************************************************/

float Vectorf::x()
{
	if(dimension>0)
	{
		return coordinates[0];
	}
}

float Vectorf::y()
{
	if(dimension>1)
	{
		return coordinates[1];
	}
}

float Vectorf::z()
{
	if(dimension>2)
	{
		return coordinates[2];
	}
}

float Vectorf::w()
{
	if(dimension>3)
	{
		return coordinates[3];
	}
}

void Vectorf::x(float aX)
{
	if(dimension>0)
	{
		coordinates[0]=aX;
	}
}

void Vectorf::y(float aY)
{
	if(dimension>1)
	{
		coordinates[1]=aY;
	}
}

void Vectorf::z(float aZ)
{
	if(dimension>2)
	{
		coordinates[2]=aZ;
	}
}

void Vectorf::w(float aW)
{
	if(dimension>3)
	{
		coordinates[3]=aW;
	}
}

float * Vectorf::Array()
{
	return coordinates;
}

Vectorf Vectorf::operator-(const Vectorf & v)
{
    Vectorf vec(*this);

    if(dimension==v.dimension)
    {
        for(int i=0;i<dimension;i++)
        {
            vec.coordinates[i]=vec.coordinates[i]-v.coordinates[i];
        }
    }
    return vec;
}

Vectorf  Vectorf::operator+(const Vectorf & v)
{
    Vectorf vec(*this);

    if(dimension==v.dimension)
    {
        for(int i=0;i<dimension;i++)
        {
            vec.coordinates[i]=vec.coordinates[i]+v.coordinates[i];
        }
    }

    return vec;
}


Vectorf Vectorf::Normalize()
{
    double len = Norme();
    Vectorf * out;

    if(len==0)
    {
          out= new Vectorf(0.0, 0.0, 0.0);
    }
    else
    {
          out= new Vectorf(this->x()/len,this->y()/len, this->z()/len);
    }

    return *out;
}

Vectorf Vectorf::Inverse()
{
    Vectorf vec (0.0,0.0,0.0);

    for(int i=0;i<dimension;i++)
    {
        vec.coordinates[i]=-coordinates[i];
    }
    return vec;
}

float Vectorf::Norme()
{
    float sum=0;
	
    for(int i=0;i<dimension;i++)
    {
        sum+=pow(coordinates[i],2);
    }
    return sqrt(sum);
}

Vectorf Vectorf::operator *(const Vectorf & v)
{
     Vectorf vec(*this);

	if(dimension==v.dimension)
	{
		for(int i=0;i<dimension;i++)
		{
                        vec.coordinates[i]=vec.coordinates[i]*v.coordinates[i];
		}
	}
       
        return vec;
}

void Vectorf::Print()
{
    for(int i=0;i<dimension;i++)
    {
        printf("%f ",coordinates[i]);
    }
    printf(" \n");
}

Vectorf Vectorf::operator*(float val)
{
    Vectorf vec(*this);

	for(int i=0;i<dimension;i++)
	{
                vec.coordinates[i]=vec.coordinates[i]*val;
	}
	
        return vec;
}

Vectorf Vectorf::operator /(float val)
{
    Vectorf vec(*this);

    for(int i=0;i<dimension;i++)
    {
        vec.coordinates[i]=vec.coordinates[i]/val;
    }

    return vec;
}

Vectorf & Vectorf::operator=(const Vectorf & v)
{

    if(dimension!=-1)
    {
        delete coordinates;
    }
    dimension=v.dimension;
    InitArray(v.coordinates);
    return *this;
}

/*

Vectorf & Vectorf::operator+(const Vectorf & argVector)
{
	Vectorf vec;
        x+=argVector.x;
        y+=argVector.y;
        z+=argVector.z;

        return *this;
}


bool Vectorf::operator ==(const Vectorf & argV)
{
    if(x==argV.x)
    {
        if(y==argV.y)
        {
            if(z==argV.z)
            {
                return true;
            }
        }
    }

    return false;
}



*/
/***********************************************************************/
/*                      Méthodes                                       */
/***********************************************************************/
/*
void Vectorf::Set(float aX, float aY, float aZ)
{
	x=aX;
	y=aY;
	z=aZ;
 }
 
 void Vectorf::Set(float * aF)
{
	x=aF[0];
	y=aF[1];
	z=aF[2];
 }


float * Vectorf::ToArray()
{
	float * fa= new float [3];	//fa pour "float array"
		fa[0]=x;
		fa[1]=y;
		fa[2]=z;
	return fa;
}

int Vectorf::Collide(Vectorf aVertex)
{
    Vectorf u=CalculVecteur(*this,aVertex);

    if(u.Norme()<1)
    {
        return true;
    }
    return false;
}


*/
/***********************************************************************/
/*                      Méthodes statiques                             */
/***********************************************************************/
/*
float Vectorf::Angle(Vectorf u, Vectorf v)
{

    return asin(
                    (Vectorf::ProduitVectoriel(u,v)).z
                    /
                   (u.Norme()*v.Norme())
                );
}
*/

float Vectorf::ProduitScalaire(Vectorf u, Vectorf v)
{
    return (float)((u.x()*v.x())+(u.y()*v.y())+(u.z()*v.z()));
}

Vectorf Vectorf::IntersectionPlan(Vectorf u, Vectorf lineVertex, Vectorf normalPlane, Vectorf planeVertex)
{
    printf("u :  x : %f, y: %f, z : %f \n",u.x(),u.y(),u.z());
    printf("vLine : x : %f, y: %f, z : %f \n",lineVertex.x(),lineVertex.y(),lineVertex.z());
    printf("vplan : x : %f, y: %f, z : %f \n",planeVertex.x(),planeVertex.y(),planeVertex.z());

    Vectorf v(planeVertex.x()-lineVertex.x(), planeVertex.y()-lineVertex.y(), planeVertex.z()-lineVertex.z());

    printf("vLine-plan : x : %f, y: %f, z : %f \n",v.x(),v.y(),v.z());
    float val;

    Vectorf vNormal=u.Normalize();
    printf("uNormal :  x : %f, y: %f, z : %f \n",vNormal.x(),vNormal.y(),vNormal.z());

    printf("produitSclaire plane.v %f \n",ProduitScalaire(normalPlane,v));
    printf("produitSclaire plane.u %f \n",ProduitScalaire(normalPlane,u));

    val= ProduitScalaire(normalPlane,v)/ProduitScalaire(normalPlane,u);

    printf("val : %f \n",val);
    return u*val;
}



Vectorf  Vectorf::ProduitVectoriel(Vectorf u, Vectorf v)
{
    Vectorf * tempVector= new Vectorf(0.0,0.0,0.0);

    tempVector->x(  (u.y()*v.z())-(v.y()*u.z()));
    tempVector->y(  (u.z()*v.x())-(v.z()*u.x()));
    tempVector->z(  (u.x()*v.y())-(v.x()*u.y()));

    return *tempVector;
}

/*

Vectorf & Vectorf::CalculVecteur(Vectorf A, Vectorf B)
{
    Vectorf * tempVector= new Vectorf();

    tempVector->x=  B.x-A.x;
    tempVector->y=  B.y-A.y;
    tempVector->z=  B.z-A.z;

    return *tempVector;
}

bool Vectorf::Intersection(Vectorf A, Vectorf B, Vectorf C, Vectorf D, Vectorf * aResultat)
{
        //  Chercher l'intersection revient à résoudre l'équation ou :
        //  pAB= A+m(B-A)
        //  pCD= C+k(D-C)

        //pour lesquels pAb=pCD

        //Ensuite, on développe l'équation pour trouver les valeurs de m et k. Si les 2 sont compris entre 0 et 1
        //  alors, les segments se coupent

        float m =   (
                        (
                            ((D.x-C.x)*(A.y-C.y))-((D.y-C.y)*(A.x-C.x))
                        )
                        /
                        (
                             ((D.y-C.y)*(B.x-A.x))-((D.x-C.x)*(B.y-A.y))
                        )
                    );

        float k =
                    (
                        (
                            ((B.x-A.x)*(A.y-C.y))-((B.y-A.y)*(A.x-C.x))
                        )
                        /
                        (
                             ((D.y-C.y)*(B.x-A.x))-((D.x-C.x)*(B.y-A.y))
                        )
                    );

        aResultat->x = A.x + m*(B.x-A.x);
        aResultat->y = A.y + m*(B.y-A.y);
        aResultat->z=-1;

        if(m>0 && m<1 && k>0 && k<1)
        {
             return true;
        }
        else    { return false;}


    }



/*
    Ua=( (x4-x3)(y1-y3)-(y4-y3)(x1-x3) ) / ( (y4-y3)(x2-x1)-(x4-x3)(y2-y1));
    Ub=( (x2-x1)(y1-y3)-(y2-y1)(x1-x3) ) / ( (y4-y3)(x2-x1)-(x4-x3)(y2-y1));
*/


/*-----------------------------------------------------------------------------------------------------------------*/
/*								Pour les unsigned char										*/
/*-----------------------------------------------------------------------------------------------------------------*/

/*
Vector3uc::Vector3uc()
{
	x=y=z=0;
}

Vector3uc::Vector3uc(unsigned char argX, unsigned char argY, unsigned char argZ)
{
	x=argX;
	y=argY;
	z=argZ;
}

Vector3uc & Vector3uc::operator+(const Vector3uc & argVector)
{
    x+=argVector.x;
    y+=argVector.y;
    z+=argVector.z;
    return *this;
}

Vector3uc & Vector3uc::operator-(const Vector3uc & argVector)
{
    x-=argVector.x;
    y-=argVector.y;
    z-=argVector.z;
    return *this;
}
Vector3uc & Vector3uc::operator=(const Vector3uc & argVector)
{
    x=argVector.x;
    y=argVector.y;
    z=argVector.z;
    return *this;
}
*/
